//! 8086 指令编码器
//! 
//! 主路由器，将指令分发到各个子编码器

use crate::ast::{Instruction, Operand};
use crate::error::{AssemblerError, Result};
use crate::instruction::InstructionEncoder;
use super::mov::MovEncoder;
use super::arithmetic::ArithmeticEncoder;
use super::logical::LogicalEncoder;
use super::shift::ShiftEncoder;
use super::stack::StackEncoder;
use super::control_flow::ControlFlowEncoder;
use super::other::OtherEncoder;
use super::string::StringEncoder;

/// 8086 指令编码器
pub struct Encoder8086 {
    mov: MovEncoder,
    arithmetic: ArithmeticEncoder,
    logical: LogicalEncoder,
    shift: ShiftEncoder,
    stack: StackEncoder,
    control_flow: ControlFlowEncoder,
    other: OtherEncoder,
    string: StringEncoder,
}

impl Encoder8086 {
    /// 创建新的8086编码器
    pub fn new() -> Self {
        Self {
            mov: MovEncoder,
            arithmetic: ArithmeticEncoder,
            logical: LogicalEncoder,
            shift: ShiftEncoder,
            stack: StackEncoder,
            control_flow: ControlFlowEncoder,
            other: OtherEncoder,
            string: StringEncoder,
        }
    }

    /// 编码指令为二进制（内部实现）
    fn encode_internal(
        &self,
        chinese_instruction: &str,
        operands: &[Operand],
    ) -> Result<Vec<u8>> {
        match chinese_instruction {
            "移动" => self.mov.encode(operands),
            "交换" => self.mov.encode_xchg(operands),
            "加" | "减" | "比较" | "乘" | "除" | "有符号乘" | "有符号除" | "自增" | "自减" => 
                self.arithmetic.encode(chinese_instruction, operands),
            "与" | "或" | "异或" | "非" | "测试" => 
                self.logical.encode(chinese_instruction, operands),
            "左移" | "右移" | "算术右移" => 
                self.shift.encode(chinese_instruction, operands),
            "推入" | "弹出" => 
                self.stack.encode(chinese_instruction, operands),
            "跳转" | "调用" | "返回" | 
            "等于跳转" | "不等于跳转" | "大于跳转" | "大于等于跳转" | 
            "小于跳转" | "小于等于跳转" |
            "进位跳转" | "无进位跳转" | "溢出跳转" | "无溢出跳转" |
            "零跳转" | "非零跳转" | "符号跳转" | "无符号跳转" |
            "偶跳转" | "奇跳转" |
            "高于跳转" | "高于等于跳转" | "低于跳转" | "低于等于跳转" |
            "循环" | "等于循环" | "不等于循环" => 
                self.control_flow.encode(chinese_instruction, operands),
            "空操作" | "中断" |
            "清除进位" | "设置进位" | "取反进位" |
            "清除方向" | "设置方向" |
            "清除中断" | "设置中断" |
            "输入" | "输出" => 
                self.other.encode(chinese_instruction, operands),
            "移动字符串字节" | "移动字符串字" |
            "比较字符串字节" | "比较字符串字" |
            "扫描字符串字节" | "扫描字符串字" |
            "加载字符串字节" | "加载字符串字" |
            "存储字符串字节" | "存储字符串字" => 
                self.string.encode(chinese_instruction, operands),
            _ => Err(AssemblerError::CodeGenError {
                message: format!("8086暂不支持编码指令: {}", chinese_instruction),
            }),
        }
    }
}

impl InstructionEncoder for Encoder8086 {
    fn encode_instruction(
        &self,
        instruction: &str,
        operands: &[Operand],
    ) -> Result<Vec<u8>> {
        self.encode_internal(instruction, operands)
    }
    
    fn estimate_instruction_size(
        &self,
        instruction: &Instruction,
    ) -> Result<usize> {
        // 8086 指令大小估算
        match instruction.name.as_str() {
            "移动" => {
                // MOV 指令大小取决于操作数类型
                if instruction.operands.len() == 2 {
                    match (&instruction.operands[0], &instruction.operands[1]) {
                        (Operand::Register(_), Operand::Register(_)) => Ok(2),
                        (Operand::Register(_), Operand::Immediate(_)) => Ok(3),
                        (Operand::Register(_), Operand::Memory(_)) => Ok(3),
                        (Operand::Memory(_), Operand::Register(_)) => Ok(3),
                        _ => Ok(3),
                    }
                } else {
                    Ok(3)
                }
            }
            "交换" => {
                // XCHG 指令大小估算
                if instruction.operands.len() == 2 {
                    match (&instruction.operands[0], &instruction.operands[1]) {
                        (Operand::Register(reg1), Operand::Register(reg2)) => {
                            // 检查是否是 AX 的特殊编码
                            if (reg1 == "累加器" && reg2 != "累加器") ||
                               (reg1 != "累加器" && reg2 == "累加器") {
                                Ok(1) // XCHG AX, reg: 单字节
                            } else {
                                Ok(2) // XCHG reg, reg: 2字节
                            }
                        }
                        (Operand::Register(_), Operand::Memory(mem)) |
                        (Operand::Memory(mem), Operand::Register(_)) => {
                            // XCHG reg, mem 或 XCHG mem, reg
                            // 需要根据内存操作数计算位移大小
                            match mem.displacement {
                                Some(d) if d >= -128 && d <= 127 && d != 0 => Ok(3), // 8位位移
                                Some(_) => Ok(4), // 16位位移
                                None => Ok(2), // 无位移
                            }
                        }
                        _ => Ok(2), // 默认值
                    }
                } else {
                    Ok(2)
                }
            }
            "加" | "减" | "比较" | "与" | "或" | "异或" => {
                if instruction.operands.len() == 2 {
                    match &instruction.operands[1] {
                        Operand::Immediate(imm) if *imm >= -128 && *imm <= 127 => Ok(3),
                        Operand::Immediate(_) => Ok(4),
                        Operand::Register(_) => Ok(2),
                        _ => Ok(3),
                    }
                } else {
                    Ok(3)
                }
            }
            "测试" => {
                // TEST 指令大小估算
                if instruction.operands.len() == 2 {
                    match &instruction.operands[1] {
                        Operand::Immediate(_) => Ok(4), // TEST reg, imm16 总是4字节
                        Operand::Register(_) => Ok(2), // TEST reg, reg: 2字节
                        Operand::Memory(mem) => {
                            match mem.displacement {
                                Some(d) if d >= -128 && d <= 127 && d != 0 => Ok(3), // 8位位移
                                Some(_) => Ok(4), // 16位位移
                                None => Ok(2), // 无位移
                            }
                        }
                        _ => Ok(3),
                    }
                } else {
                    Ok(3)
                }
            }
            "乘" | "除" | "有符号乘" | "有符号除" => Ok(2), // MUL/DIV/IMUL/IDIV reg (2字节：操作码1 + ModR/M 1)
            "非" => Ok(2), // NOT reg (2字节：操作码1 + ModR/M 1)
            "左移" | "右移" | "算术右移" => {
                if instruction.operands.len() == 2 {
                    match &instruction.operands[1] {
                        Operand::Immediate(1) => Ok(2), // 移位1位：2字节
                        Operand::Immediate(_) => Ok(3), // 移位imm8：3字节
                        Operand::Register(_) => Ok(2),  // 移位CL：2字节
                        _ => Ok(3),
                    }
                } else {
                    Ok(3)
                }
            }
            "自增" | "自减" => Ok(1),
            "推入" | "弹出" => Ok(1),
            "跳转" => Ok(3), // JMP rel16
            "调用" => {
                // CALL 指令大小取决于操作数类型
                if instruction.operands.is_empty() {
                    Ok(3) // 默认：CALL rel16
                } else {
                    match &instruction.operands[0] {
                        Operand::Register(_) => Ok(2), // CALL reg (2字节)
                        Operand::Immediate(_) => Ok(3), // CALL rel16 (3字节)
                        Operand::Label(_) => Ok(3), // CALL label (3字节，标签会转换为rel16)
                        _ => Ok(3),
                    }
                }
            }
            "返回" => {
                if instruction.operands.is_empty() {
                    Ok(1) // RET (1字节)
                } else {
                    Ok(3) // RET imm16 (3字节)
                }
            }
            "等于跳转" | "不等于跳转" | "大于跳转" | "大于等于跳转" | 
            "小于跳转" | "小于等于跳转" |
            "进位跳转" | "无进位跳转" | "溢出跳转" | "无溢出跳转" |
            "零跳转" | "非零跳转" | "符号跳转" | "无符号跳转" |
            "偶跳转" | "奇跳转" |
            "高于跳转" | "高于等于跳转" | "低于跳转" | "低于等于跳转" |
            "循环" | "等于循环" | "不等于循环" => 
                Ok(2), // LOOP 系列指令都是 rel8（2字节：操作码1 + 偏移1）
            "空操作" |
            "清除进位" | "设置进位" | "取反进位" |
            "清除方向" | "设置方向" |
            "清除中断" | "设置中断" |
            "移动字符串字节" | "移动字符串字" |
            "比较字符串字节" | "比较字符串字" |
            "扫描字符串字节" | "扫描字符串字" |
            "加载字符串字节" | "加载字符串字" |
            "存储字符串字节" | "存储字符串字" => Ok(1), // 所有字符串指令都是单字节
            "输入" | "输出" => {
                // IO指令大小取决于操作数类型
                if instruction.operands.len() == 2 {
                    match (&instruction.operands[0], &instruction.operands[1]) {
                        (Operand::Register(_), Operand::Register(_)) => Ok(1), // IN/OUT reg, DX (1字节)
                        (Operand::Register(_), Operand::Immediate(_)) => Ok(2), // IN reg, imm8 (2字节)
                        (Operand::Immediate(_), Operand::Register(_)) => Ok(2), // OUT imm8, reg (2字节)
                        _ => Ok(2),
                    }
                } else {
                    Ok(2)
                }
            }
            _ => Ok(3), // 默认值
        }
    }
    
    fn get_jump_offset_range(
        &self,
        instruction: &str,
    ) -> Option<(i64, i64)> {
        match instruction {
            "等于跳转" | "不等于跳转" | "大于跳转" | "大于等于跳转" | 
            "小于跳转" | "小于等于跳转" |
            "进位跳转" | "无进位跳转" | "溢出跳转" | "无溢出跳转" |
            "零跳转" | "非零跳转" | "符号跳转" | "无符号跳转" |
            "偶跳转" | "奇跳转" |
            "高于跳转" | "高于等于跳转" | "低于跳转" | "低于等于跳转" |
            "循环" | "等于循环" | "不等于循环" => {
                // LOOP 系列指令：8位偏移（-128 到 +127）
                Some((-128, 127))
            }
            "跳转" | "调用" => {
                // JMP/CALL：16位偏移（-32768 到 +32767）
                Some((-32768, 32767))
            }
            _ => None,
        }
    }
    
    fn address_size(&self) -> usize {
        2 // 8086 使用 16 位地址
    }
    
    fn is_conditional_jump(&self, name: &str) -> bool {
        matches!(
            name,
            "等于跳转" | "不等于跳转" | "大于跳转" | "大于等于跳转" | 
            "小于跳转" | "小于等于跳转" |
            "进位跳转" | "无进位跳转" | "溢出跳转" | "无溢出跳转" |
            "零跳转" | "非零跳转" | "符号跳转" | "无符号跳转" |
            "偶跳转" | "奇跳转" |
            "高于跳转" | "高于等于跳转" | "低于跳转" | "低于等于跳转"
        )
    }
}

impl Encoder8086 {
    /// 编码指令为二进制（公开方法，向后兼容）
    /// 
    /// 直接接受中文指令名称，映射到8086二进制编码
    pub fn encode_instruction(
        &self,
        chinese_instruction: &str,
        operands: &[Operand],
    ) -> Result<Vec<u8>> {
        self.encode_internal(chinese_instruction, operands)
    }
}

impl Default for Encoder8086 {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encode_mov() {
        let encoder = Encoder8086::new();
        let operands = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        let result = encoder.encode_instruction("移动", &operands).unwrap();
        assert_eq!(result, vec![0x89, 0xC3]);
    }

    #[test]
    fn test_encode_add() {
        let encoder = Encoder8086::new();
        let operands = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        let result = encoder.encode_instruction("加", &operands).unwrap();
        assert_eq!(result, vec![0x01, 0xC3]);
    }

    #[test]
    fn test_encode_invalid_instruction() {
        let encoder = Encoder8086::new();
        let operands = vec![Operand::Register("累加器".to_string())];
        let result = encoder.encode_instruction("无效指令", &operands);
        assert!(result.is_err());
    }

    #[test]
    fn test_encode_all_instruction_types() {
        let encoder = Encoder8086::new();
        
        // 测试各种指令类型都能正确路由
        let mov_ops = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        assert!(encoder.encode_instruction("移动", &mov_ops).is_ok());
        
        let add_ops = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        assert!(encoder.encode_instruction("加", &add_ops).is_ok());
        
        let and_ops = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        assert!(encoder.encode_instruction("与", &and_ops).is_ok());
        
        let push_ops = vec![Operand::Register("累加器".to_string())];
        assert!(encoder.encode_instruction("推入", &push_ops).is_ok());
        
        let jmp_ops = vec![Operand::Immediate(100)];
        assert!(encoder.encode_instruction("跳转", &jmp_ops).is_ok());
        
        let nop_ops = vec![];
        assert!(encoder.encode_instruction("空操作", &nop_ops).is_ok());
        
        let xchg_ops = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        assert!(encoder.encode_instruction("交换", &xchg_ops).is_ok());
    }

    #[test]
    fn test_encode_xchg() {
        let encoder = Encoder8086::new();
        let operands = vec![
            Operand::Register("累加器".to_string()),
            Operand::Register("基址".to_string()),
        ];
        let result = encoder.encode_instruction("交换", &operands).unwrap();
        // XCHG AX, BX = 0x93
        assert_eq!(result, vec![0x93]);
    }
}

